package com.oner365.test.futureDemo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 串行方式执行 洗水壶->烧开水->洗茶壶->洗茶杯->拿茶叶->泡茶
 * 并行方式执行 洗水壶->烧开水---------->
 *                                    泡茶
 *            洗茶壶->洗茶杯->拿茶叶-->
 * 只是通过这个列子做简单的Future、Callable、FutureTask、ExecutorService、RunnableFuture、Runnable的理解
 */
public class MakeTeaDemo {
  
  private static final Logger LOGGER = LoggerFactory.getLogger(MakeTeaDemo.class);

  
  public static void main(String[] args) throws InterruptedException, ExecutionException {
    serialMakeTea();
    System.err.println("------------并行parallel---------------");
    parallelMakeTea();
  }

  public static void serialMakeTea() throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    Future<String> future1 = executorService.submit(teaTask1());
    Future<String> future2 = executorService.submit(teaTask2());
    LOGGER.info("future1:{}",future1.get());
    LOGGER.info("future2:{}",future2.get());
    LOGGER.info("开始泡茶");
    TimeUnit.SECONDS.sleep(1);
    executorService.shutdown();
  }

  public static Callable<String> teaTask1() {
    Callable<String> callable = () -> {
      LOGGER.info("teaTask1:洗水壶");
      TimeUnit.SECONDS.sleep(1);
      LOGGER.info("teaTask1:烧开水");
      TimeUnit.SECONDS.sleep(15);
      return "水已烧好";
    };
    return callable;
  }

  public static Callable<String> teaTask2() {
    Callable<String> callable = () -> {
      LOGGER.info("teaTask2:洗茶壶");
      TimeUnit.SECONDS.sleep(1);
      LOGGER.info("teaTask2:洗茶杯");
      TimeUnit.SECONDS.sleep(1);
      LOGGER.info("teaTask2:拿茶叶");
      TimeUnit.SECONDS.sleep(2);
      return "茶已拿到";
    };
    return callable;
  }

  public static void parallelMakeTea() throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    Future<String> future2 = executorService.submit(new Task2());
    executorService.submit(new Task1(future2));
    executorService.shutdown();
  }


  public static class Task1 implements Callable<String> {
    Future<String> t2;

    public Task1(Future<String> t2) {
      this.t2 = t2;
    }

    @Override
    public String call() throws Exception {
      LOGGER.info("teaTask3:洗水壶");
      TimeUnit.SECONDS.sleep(1);
      LOGGER.info("teaTask3:烧开水");
      TimeUnit.SECONDS.sleep(15);
      String result = t2.get();
      LOGGER.info("teaTask3:水已烧好!" + result + "开始泡茶");
      TimeUnit.SECONDS.sleep(1);
      return "上茶";
    }

  }
  
  public static class Task2 implements Callable<String> {
    @Override
    public String call() throws Exception {
      LOGGER.info("teaTask2:洗茶壶");
      TimeUnit.SECONDS.sleep(1);
      LOGGER.info("teaTask2:洗茶杯");
      TimeUnit.SECONDS.sleep(1);
      LOGGER.info("teaTask2:拿茶叶");
      TimeUnit.SECONDS.sleep(2);
      return "茶已拿到";
    }

  }

}
